package games.chasingdodo;

import games.chasingdodo.GameStateChasingDodo.OnGameStateUpdateListener;
import games.common.Field;

import java.io.IOException;
import java.util.HashSet;

import network.NetworkManager;

import org.andengine.audio.music.Music;
import org.andengine.audio.music.MusicFactory;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.WakeLockOptions;
import org.andengine.engine.options.resolutionpolicy.FillResolutionPolicy;
import org.andengine.entity.IEntity;
import org.andengine.entity.scene.IOnSceneTouchListener;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.util.FPSLogger;
import org.andengine.input.sensor.acceleration.AccelerationData;
import org.andengine.input.sensor.acceleration.IAccelerationListener;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.ui.activity.SimpleBaseGameActivity;

import configuration.Constants;
import protocol.listeners.*;
import protocol.Print;
import protocol.RoomConnection;
import protocol.User;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;

public class ChasingDodoActivity extends SimpleBaseGameActivity implements IOnSceneTouchListener, OnNewMessageListener, IAccelerationListener, OnGameStateUpdateListener, EntityRemover {

	/**
	 * Constants
	 */
	public static final int CAMERA_WIDTH = 1080;
	public static final int CAMERA_HEIGHT = 720;
	private static final int COLD_DOWN_TIME_REDUCTION = 20;
	private static final int POSITION_CORN_X = 165;

	/**
	 * Entities
	 */
	private Scene scene;
	private Field background;
	private WindowLayer windowLayer;
	private Dodo dodo;
	private Music music;
	private HashSet<Egg> eggs;
	private CornCreator cornCreator;

	/**
	 * Variables
	 */
	private int eggCount;
	private long lastEggTrow;
	private float inclination;
	private int minimumThrowingEggTime = 1200;

	/**
	 * Connection
	 */
	private RoomConnection room;
	private RoomManagerDodoGame roomManager;

	/**
	 * Configuration
	 */
	private boolean isRacing;
	private boolean onGoingGame = true;
	private boolean gameStoppedByOther = false;
	private GameStateChasingDodo gameState;

	/**
	 * Helpers
	 */
	private MoveDetector moveDetector;

	@Override
	protected void onCreate(Bundle pSavedInstanceState) {
		// Game mode
		Bundle bundle = getIntent().getExtras();
		String message = bundle.getString(Constants.MODE);
		if(message == null)
			finish();
		else if(message.equals(Constants.MODE_RACING)) {
			isRacing = true;
		} else if(message.equals(Constants.MODE_ATTACKING)) {
			isRacing = false;
		} else
			finish();
		int round = bundle.getInt(Constants.ROUND);
		Toast.makeText(getApplicationContext(), "ROUND "+(round+1), 0).show();

		// Creating the movement recognizer
		this.moveDetector = new MoveDetector();

		// Registering the message listener
		NetworkManager.INSTANCE.setListener(this);

		// Creating the game state handler
		gameState = new GameStateChasingDodo(roomManager, isRacing, round);
		gameState.addListener(this);

		super.onCreate(pSavedInstanceState);
	}

	@Override
	public EngineOptions onCreateEngineOptions() {
		Camera mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		EngineOptions engineOptions = new EngineOptions(true,ScreenOrientation.LANDSCAPE_FIXED, new FillResolutionPolicy(), mCamera);
		engineOptions.setWakeLockOptions(WakeLockOptions.SCREEN_ON);
		engineOptions.getAudioOptions().setNeedsSound(true);
		engineOptions.getAudioOptions().setNeedsMusic(true);
		return engineOptions;
	}

	@Override
	protected void onCreateResources() throws IOException {

		// Background
		background = new Field();		
		background.onCreateResourcesBackground(getTextureManager(), this);

		// Dodo
		dodo = new Dodo(roomManager, CAMERA_WIDTH, isRacing);
		roomManager.dodo = dodo;
		dodo.onCreateResources(getTextureManager(), getEngine(), this);

		// Window layer
		windowLayer = new WindowLayer(CAMERA_WIDTH, CAMERA_HEIGHT);
		windowLayer.onCreateResources(getTextureManager(), getFontManager(), getAssets(), this);

		// Egg resources
		Egg.onCreateResources(getTextureManager(), getEngine(), this, CAMERA_WIDTH, CAMERA_HEIGHT);
		this.eggs = new HashSet<Egg>();

		// Corn resources
		Corn.onCreateResources(getTextureManager(), getEngine(), this);

		try {
			music = MusicFactory.createMusicFromAsset(mEngine.getMusicManager(), this,"sonido/bleachSoundtrackDodoDance.mp3");
			music.setLooping(true);
			music.setVolume(0.8f);
		} catch (IOException e) {}
	}

	@Override
	protected Scene onCreateScene() {

		this.mEngine.registerUpdateHandler(new FPSLogger());
		final VertexBufferObjectManager vertexBufferObjectManager = this.getVertexBufferObjectManager();
		scene = new Scene();

		// Background
		background.onCreateSceneBackground(vertexBufferObjectManager);		
		scene.setBackground(background.getBackground());

		// Dodo
		dodo.onCreateScene(getVertexBufferObjectManager(), scene, CAMERA_WIDTH/2, 140);

		// Window Layer
		windowLayer.onCreateScene(getVertexBufferObjectManager(), scene, CAMERA_WIDTH/2, CAMERA_HEIGHT/2);
		gameState.addListener(windowLayer);
		if(isRacing) {
			windowLayer.countDownAnimation(5, isRacing, roomManager);
			gameState.startGameIn(5);
		}

		// Corn creator
		cornCreator = new CornCreator(isRacing ? roomManager : null, gameState, this, dodo.getEntity(), scene, CAMERA_WIDTH + 300, POSITION_CORN_X, CAMERA_HEIGHT - 50);

		// Listener to scene
		scene.setOnSceneTouchListener(this);

		// Starting music
		music.play();

		return scene;
	}

	// ************************************ GAME THREAD ************************************

	public void gameThread() {
		if(isRacing) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					while(onGoingGame) {
						long sleepTime = System.currentTimeMillis();
						runOnUpdateThread(new Runnable() {
							public void run() {
								Egg eggToRemove = null;
								for (Egg egg : eggs) {
									if(egg.collide(dodo.getEntity())) {
										gameState.eggCrash();
										eggToRemove = egg;
										dodo.scream(Dodo.SOUND_TURKEY);
									}
								}
								if(eggToRemove != null) {
									eggs.remove(eggToRemove);
									//removeEntitiy(scene, eggToRemove.getEntity());
								}
							}
						});
						cornCreator.work();
						sleepTime = 100 - (System.currentTimeMillis() - sleepTime);
						if(sleepTime > 0)
							try {Thread.sleep(sleepTime);} catch (InterruptedException e) {}
					}
				}
			}).start();
		} else {
			new Thread(new Runnable() {
				@Override
				public void run() {
					while(onGoingGame) {
						long sleepTime = System.currentTimeMillis();
						cornCreator.work();
						sleepTime = 100 - (System.currentTimeMillis() - sleepTime);
						if(sleepTime > 0)
							try {Thread.sleep(sleepTime);} catch (InterruptedException e) {}
					}
				}
			}).start();
		}
	}

	public void addEgg(int eggId, boolean leftTrueFallingFalse, int x, int y, int totalTime) {
		Egg egg = new Egg(this, roomManager, false, eggId, eggs);
		if(eggId > eggCount && eggs.add(egg)) {
			eggCount = eggId;
			Print.print("huevos", "Agregando el huevo "+eggId);
			egg.throwEgg(getVertexBufferObjectManager(), scene, x, y, leftTrueFallingFalse, totalTime);
		}
	}

	public void crashEgg(int eggId, int x, int y) {
		Egg eggToRemove = null;
		for (Egg egg : eggs) {
			if(egg.eggId == eggId) {
				eggToRemove = egg;
				egg.crash(x, y);
				break;
			}
		}
		if(eggs.remove(eggToRemove))
			dodo.scream(Dodo.SOUND_TURKEY);
	}

	public void chooseCorn(int counter, int chosenPath) {
		this.cornCreator.choosePath(counter, chosenPath);
	}

	public void gameControlMessage(int control, int life, int corn) {
		this.gameState.onNewControlMessage(control, life, corn);
	}

	public void beginningGame(Integer seconds) {
		windowLayer.countDownAnimation(seconds, false, null);
		gameState.startGameIn(5);
	}

	// ************************************ GAME THREAD ************************************

	// ************************************* LISTENERS *************************************

	@Override
	public boolean onSceneTouchEvent(Scene pScene, TouchEvent touchEvent) {
		if(isRacing) {
			final int xy = moveDetector.touch(touchEvent);
			if(xy != -1) {
				switch (moveDetector.getMoveType()) {
				case MoveDetector.MOVE_LEFT:
					break;
				case MoveDetector.MOVE_RIGHT:
					break;
				case MoveDetector.MOVE_UP:
					dodo.jump();
					break;
				case MoveDetector.MOVE_DOWN:
					break;
				}
			}
		} else if(gameState.isGameEnabled()) {
			final int xy = moveDetector.touch(touchEvent);
			if(xy != -1 && System.currentTimeMillis() - lastEggTrow > minimumThrowingEggTime) {
				minimumThrowingEggTime -= COLD_DOWN_TIME_REDUCTION;
				lastEggTrow = System.currentTimeMillis();
				switch (moveDetector.getMoveType()) {
				case MoveDetector.MOVE_LEFT:
					runOnUpdateThread(new Runnable() {
						@Override
						public void run() {
							Egg egg = new Egg(ChasingDodoActivity.this, roomManager, true, eggCount++, eggs);
							egg.throwEgg(getVertexBufferObjectManager(), scene, CAMERA_WIDTH + 400, xy);
							eggs.add(egg);
						}
					});
					break;
				case MoveDetector.MOVE_RIGHT:
					break;
				case MoveDetector.MOVE_UP:
					break;
				case MoveDetector.MOVE_DOWN:
					runOnUpdateThread(new Runnable() {
						@Override
						public void run() {
							Egg egg = new Egg(ChasingDodoActivity.this, roomManager, true, eggCount++, eggs);
							egg.throwEgg(getVertexBufferObjectManager(), scene, xy, CAMERA_HEIGHT + 300);
							eggs.add(egg);
						}
					});
					break;
				}
			}
		}
		return false;
	}

	@Override
	public void onAccelerationAccuracyChanged(AccelerationData pAccelerationData) {}

	@Override
	public void onAccelerationChanged(AccelerationData pAccelerationData) {
		if(isRacing) {
			dodo.setHorizontalMove(pAccelerationData.getX());
		}
	}

	// ************************************* LISTENERS *************************************

	// ********************************** PROTOCOL EVENTS **********************************

	@Override
	public int onNewMessage(final String message, final User user) {

		runOnUpdateThread(new Runnable() {

			@Override
			public void run() {
				roomManager.onNewMessage(message);
			}
		});
		return message.length();
	}

	@Override
	public void getRoomConnection(RoomConnection connection) {
		this.room = connection;
		this.roomManager = new RoomManagerDodoGame(this, room, isRacing);
	}

	@Override
	public void onCloseConnection() {}

	// ********************************** PROTOCOL EVENTS **********************************

	// *************************************** UTIL ****************************************

	public void removeEntitiy(final IEntity from, final IEntity toRemove) {
		runOnUpdateThread(new Runnable() {
			@Override
			public void run() {
				from.detachChild(toRemove);
			}
		});
	}

	@Override
	public void removeEntitiyFromScene(final IEntity toRemove) {
		runOnUpdateThread(new Runnable() {
			@Override
			public void run() {
				scene.detachChild(toRemove);
			}
		});
	}

	// *************************************** UTIL ****************************************

	// ************************************ GAME STATE *************************************

	@Override
	public void onLifeChanged(int life) {}

	@Override
	public void onCornChanged(int corn) {}

	@Override
	public void onBeginGame(boolean gameMode) {
		gameThread();
	}

	@Override
	public void onChangePlayingMode(final boolean gameMode, int corn) {
		onGoingGame = false;
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {Thread.sleep(5000);} catch (InterruptedException e) {}
				Intent intent = new Intent(ChasingDodoActivity.this, ChasingDodoActivity.class);
				if(gameMode) {
					intent.putExtra(Constants.MODE, Constants.MODE_ATTACKING);
				} else {
					intent.putExtra(Constants.MODE, Constants.MODE_RACING);
				}
				intent.putExtra(Constants.ROUND, 1);
				startActivity(intent);
				finish();
				gameState.stopGame();
			}
		}).start();
	}

	@Override
	public void onFinishGame(boolean gameMode, final int myScore, final int enemyScore) {
		onGoingGame = false;
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {Thread.sleep(5000);} catch (InterruptedException e) {}
				gameState.stopGame();
			}
		}).start();
	}

	@Override
	public void onReplay(boolean gameMode) {}

	@Override
	public void onLostConnection() {}

	@Override
	public void onGameStopedByOther() {
		if(!gameStoppedByOther) {
			gameStoppedByOther = true;
			onGoingGame = false;
			runOnUiThread(new Runnable() {

				@Override
				public void run() {
					AlertDialog.Builder alert = new AlertDialog.Builder(ChasingDodoActivity.this);
					alert.setTitle("Alert");
					alert.setMessage("Game was stopped by the other player");
					alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int whichButton) {
							onGoingGame = false;
							gameState.stopGame();
							finish();
						}
					});
					alert.show();
				}
			});
		}

		new Thread(new Runnable() {

			@Override
			public void run() {
				try {Thread.sleep(5000);} catch (InterruptedException e) {}
				onGoingGame = false;
				gameState.stopGame();
				finish();
			}
		}).start();
	}

	public void disconnectionMessage() {
		gameState.disconnection();
	}

	// ************************************ GAME STATE *************************************

	// ************************************ LIFE CYCLE *************************************

	@Override
	public void onResumeGame() {
		super.onResumeGame();
		this.music.resume();
		this.gameState.requestResume();
		this.enableAccelerationSensor(this);
	}

	@Override
	public void onPauseGame() {
		super.onPauseGame();
		this.music.pause();
		this.gameState.requestPause();
		this.disableAccelerationSensor();
	}

	@Override
	protected void onDestroy() {
		this.gameState.stopGame();
		this.onGoingGame = false;
		super.onDestroy();
	}

	@Override
	public void onBackPressed() {
		AlertDialog.Builder alert = new AlertDialog.Builder(this);
		alert.setTitle("Stop game");
		alert.setMessage("Do you really want to stop the game?");
		alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
				gameState.disconnectGame();
				finish();
			}
		});
		alert.setNegativeButton("No", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
				// Do nothing
			}
		});
		alert.show();
	}

	// ************************************ LIFE CYCLE *************************************
}
